package com.myalibaba.example;
import org.junit.Test;

import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;

/**
 * 主要区别
 * 线程安全性：
 * ConcurrentHashMap：设计为在多线程环境中使用，是线程安全的。
 * HashMap：不是线程安全的，多个线程同时访问和修改会导致数据不一致。
 *
 * 锁机制：
 * ConcurrentHashMap：使用了分段锁机制（Java 8及以后的版本使用了CAS和synchronized来保证并发性），在高并发环境下性能更好。
 * HashMap：在并发环境下需要外部同步，通常使用synchronized关键字来实现，但这样会降低性能。
 *
 * 性能：
 * ConcurrentHashMap：在高并发场景下性能优越，因为它的设计避免了全表锁，允许更高的并发度。
 * HashMap：在单线程环境下性能较好，但在多线程环境下性能差，且容易出现问题。
 */
public class ConcurrentHashMapExample {
    private static Map<String, Integer> map = new ConcurrentHashMap<>();

    /**
     * 在多线程环境下能够正确地保证线程安全，最终的Map大小是预期的3000。
     * ConcurrentHashMap使用了复杂的锁机制和并发控制手段，保证了在多线程环境下的线程安全性。每个线程可以独立地进行操作而不会互相干扰，从而保证了数据的一致性。
     */
    public static void main(String[] args) {
        //创建一个实现了Runnable接口的匿名类实例。Runnable接口是一个函数式接口，它只有一个抽象方法run()，可以用Lambda表达式来实现。
        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                map.put(Thread.currentThread().getName() + i, i);
            }
        };

        Thread thread1 = new Thread(task, "Thread-1");//一个线程执行一次run
        Thread thread2 = new Thread(task, "Thread-2");
        Thread thread3 = new Thread(task, "Thread-3");

        thread1.start();
        thread2.start();
        thread3.start();

        try {
            thread1.join();
            thread2.join();
            thread3.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Size of map: " + map.size());
    }




    private static Map<String, Integer> hashmap = new HashMap<>();

    /**
     * 在多线程环境下会导致数据不一致，HashMap的大小不确定，可能会小于预期值。
     * 由于HashMap不是线程安全的，多个线程同时执行put操作时，会导致内部数据结构的破坏和数据丢失。
     */
    @Test
    public  void test() {
        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                hashmap.put(Thread.currentThread().getName() + i, i);
            }
        };

        Thread thread1 = new Thread(task, "Thread-1");
        Thread thread2 = new Thread(task, "Thread-2");
        Thread thread3 = new Thread(task, "Thread-3");

        thread1.start();
        thread2.start();
        thread3.start();

        try {
            thread1.join();
            thread2.join();
            thread3.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Size of map: " + hashmap.size());
    }
}
